package org.liu.simpleTank;

import java.util.EventObject;
import java.util.LinkedList;
import java.util.List;

import org.liu.simpleTank.Bullet.BulletListener;
import org.liu.simpleTank.Bullet.HitEvent;
import org.liu.simpleTank.Tank.TankListener;
import org.liu.simpleTank.Element.ElementListener;

public class FireManager {
	private Game game;
	private Tank tank;
	private List<Bullet> bullets;
	{
		bullets = new LinkedList<Bullet>();
	}

	private TankListener fireListener;
	private BulletListener hitListener;
	{
		fireListener = new TankListener() {
			@Override
			public void fire(EventObject e) {
				Tank t = (Tank)e.getSource();
				if (bullets.size() < getTankBulletLimit(t)) {
					// bullet position
					Position p = getBulletPosition(t);
					// bullet speed 
					double speed = tank.getLife() > 1 ? Bullet.SPEED_FAST : Bullet.SPEED_NORMAL;
					Bullet b = game.placeBullet(speed, p.row, p.col, t.direction);
					bullets.add(b);
					b.addListener(hitListener);
					b.addElementListener(new ElementListener() {
						@Override
						public void destroyed(EventObject e) {
							FireManager.this.bullets.remove(((Bullet)e.getSource()));
						}
					});
				}
			}
		};
		
		hitListener = new BulletListener() {
			@Override
			public void hit(HitEvent e) {
				Hittable[] ts = e.getTargets();
				boolean destroy = false; // whether bullet should be destroyed
				boolean tankHit = false; // a bullet should hit at most one tank
				for(int i = 0; i < ts.length; i++) {
					Hittable el = ts[i]; 
					switch(((Element)el).type) {
					case CONSTS.TANK_1:
					case CONSTS.TANK_2:
					case CONSTS.TANK_3:
						if(tank.type == CONSTS.TANK_PLAYER1 || tank.type == CONSTS.TANK_PLAYER2) {
							el.hit(); 
							destroy = true;
							tankHit = true;
						} else {
							destroy = false;
						}
						break;
					case CONSTS.TANK_PLAYER1:
					case CONSTS.TANK_PLAYER2:
						if(tank.type == CONSTS.TANK_1 || tank.type == CONSTS.TANK_2 ||
						tank.type == CONSTS.TANK_3) {
							el.hit(); 
							destroy = true;
							tankHit = true;
						} else {
							destroy = false;
						}
						break;
					case CONSTS.STEEL:
						if(tank.getLife() >= 4)
							el.hit();
						destroy = true;
						break;
					case CONSTS.HOME:
					case CONSTS.BRICK: el.hit(); destroy = true; break;
					case CONSTS.GRASS:
						// tank level 5 ( with strong enough power
						// that even grass can be destroyed )
						if(tank.getLife() >= 5)
							el.hit();
						break;
					case CONSTS.BULLET:
						if(!bullets.contains(el)) el.hit();
					default:
						break;
					}
					if(tankHit)
						break;
				}
				e.setDestroy(destroy);
			}
		};
	}
	
	public FireManager(Game g, Tank t) {
		game = g;
		tank = t;
		t.addListener(fireListener);
	}
	
	private static Position getBulletPosition(Tank t) {
		switch(t.direction) {
		default:
		case CONSTS.UP:
			return new Position(t.row, t.col);
		case CONSTS.RIGHT:
			return new Position(t.row, t.col + t.w - 1);
		case CONSTS.DOWN:
			return new Position(t.row + t.h - 1, t.col);
		case CONSTS.LEFT:
			return new Position(t.row, t.col);
		}
	}
	
	private static int getTankBulletLimit(Tank t) {
		return t.getLife() > 1 ? 2 : 1;
	}
	
	private static class Position {
		public int row;
		public int col;
		public Position(int row, int col) {
			this.row = row;
			this.col = col;
		}
	}
}
